package service

import (
	"context"
	"github.com/adshao/go-binance"
	"strconv"
	"trader-bot/src/alog"
	"trader-bot/src/config"
)
/*
type API struct {
	BaseURL  	string
	BaseURLV3	string
	PublicURL	string
	Client 		Client
}

type Client struct {
	Key 		string
	Secret 		string
}


func NewAPI(key,secret string) *API {
	api := &API{
		BaseURL:"https://www.binance.com/api/v1",
		BaseURLV3:"https://api.binance.com/api/v3",
		PublicURL:"https://www.binance.com/exchange/public/product",
		Client:Client{
			Key:key,
			Secret:secret,
		},
	}
	return api
}


func(self *API) _get(path string,param url.Values) string {
	param.Add("recvWindow", string(120000))
	return self._sign(param)
}


func (self *API) _sign(param url.Values) string{
	param.Add("timestamp",time.Now().String())
	h := param.Encode()
	b := []byte(self.Client.Secret)
	mac := hmac.New(sha256.New,b)
	mac.Write([]byte(h))
	signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
	param.Add("signature",signature)
	return param.Encode()
}
*/

type Service struct {
	account     *binance.GetAccountService
	kline       *binance.KlinesService
	getOrder    *binance.GetOrderService
	cancelOrder *binance.CancelOrderService
	order       *binance.CreateOrderService
	price       *binance.ListPricesService
	time        *binance.ServerTimeService
	listOrder   *binance.ListOpenOrdersService
}

var client =  binance.NewClient(conf.Key,conf.Secret)

func NewService() *Service{
	account  := client.NewGetAccountService()
	kline := client.NewKlinesService()
	getOrder:= client.NewGetOrderService()
	cancelOrder := client.NewCancelOrderService()
	order := client.NewCreateOrderService()
	price := client.NewListPricesService()
	listOrder := client.NewListOpenOrdersService()
	time := client.NewServerTimeService()

	if account == nil || kline == nil || getOrder == nil || cancelOrder == nil || order == nil || price == nil || listOrder == nil || time == nil {
		return nil
	}

	var service = &Service{
		account:     account,
		kline:       kline,
		getOrder:    getOrder,
		cancelOrder: cancelOrder,
		order:       order,
		price:       price,
		listOrder:	 listOrder,
		time: time,
	}
	return service
}

const Zero  = "0"

func (s *Service) GetBalance(asset string ) string {
	account ,err:= s.account.Do(context.Background())
	if err != nil {
		alog.Error(err.Error())
		return Zero
	}
	for _,j := range account.Balances {
		if j.Asset == asset {
			return j.Free
		}
	}
	return Zero
}

func (s *Service)BuyMarket(symbol string,price string,quality string) (int64, error){
	res,err := s.order.Symbol(symbol).Side(binance.SideTypeBuy).Type(binance.OrderTypeMarket).
		TimeInForce(binance.TimeInForceGTC).Quantity(quality).Price(price).Do(context.Background())
	if err != nil {
		return 0,err
	}
	return res.OrderID,nil
}

func (s *Service)BuyLimit(symbol string,price string,quality string) (int64, error){
	res,err := s.order.Symbol(symbol).Side(binance.SideTypeBuy).Type(binance.OrderTypeLimit).
		TimeInForce(binance.TimeInForceGTC).Quantity(quality).Price(price).Do(context.Background())
	if err != nil {
		return 0,err
	}
	return res.OrderID,nil
}

func (s *Service)SellMarket(symbol string,price string,quality string) (int64, error){
	res,err := s.order.Symbol(symbol).Side(binance.SideTypeSell).Type(binance.OrderTypeMarket).
		TimeInForce(binance.TimeInForceGTC).Quantity(quality).Price(price).Do(context.Background())
	if err != nil {
		return 0,err
	}
	return res.OrderID,nil
}

func (s *Service)SellLimit(symbol string,price string,quality string) (int64, error){
	res,err := s.order.Symbol(symbol).Side(binance.SideTypeSell).Type(binance.OrderTypeLimit).
		TimeInForce(binance.TimeInForceGTC).Quantity(quality).Price(price).Do(context.Background())
	if err != nil {
		return 0,err
	}
	return res.OrderID,nil
}


func (s *Service)Status(symbol string,id int64) string{
	order,err := s.getOrder.Symbol(symbol).OrderID(id).Do(context.Background())
	if err != nil {
		return ""
	}
	return order.Status
}

func (s *Service)QueryOrder(symbol string,id int64) *binance.Order{
	order,err := s.getOrder.Symbol(symbol).OrderID(id).Do(context.Background())
	if err != nil {
		return nil
	}
	return order
}

func (s *Service)Cancel(symbol string,id int64) bool {
	_,err := s.cancelOrder.Symbol(symbol).OrderID(id).Do(context.Background())
	if err != nil {
		return false
	}
	return true
}

func (s*Service) Time() int64 {
	t,e:=s.time.Do(context.Background())
	if e != nil {
		return 0
	}
	return t
}

func (s *Service)Avg(symbol string,interval string,limit int) (float64,error) {
	p,err:=s.kline.Symbol(symbol).Interval(interval).Limit(limit).Do(context.Background())
	if err != nil {
		return 0,err
	}
	var total float64
	for i,_:=range p {
		c,e:= strconv.ParseFloat(p[i].Close,64)
		if e != nil {
			return 0,e
		}
		total += c
	}
	return total / float64(limit),nil
}

func (s *Service) Cur(symbol string) float64 {
	p,err:= s.price.Do(context.Background())
	if err != nil {
		return 0
	}
	for i,_:=range p {
		if p[i].Symbol == symbol {
			p,err:= strconv.ParseFloat(p[i].Price,64)
			if err != nil {
				alog.Error(err.Error())
			}
			return p
		}
	}
	return 0
}

func (s *Service) ListOrder(symbol string) []*binance.Order{
	ol,err := s.listOrder.Symbol(symbol).Do(context.Background())
	if err != nil {
		return nil
	}
	return ol
}